<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>舵机控制系统</title>
    <style>
        :root {
            --primary-color: #2196F3;
            --hover-color: #1976D2;
            --background: #f5f5f5;
        }

        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: var(--background);
        }

        .container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            max-width: 1200px;
            margin: 0 auto;
        }

        .panel {
            background: white;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .servo-item, .action-item {
            padding: 15px;
            margin: 10px 0;
            border: 1px solid #ddd;
            border-radius: 4px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        button {
            background: var(--primary-color);
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 4px;
            cursor: pointer;
            transition: background 0.3s;
        }

        button:hover {
            background: var(--hover-color);
        }

        input[type="number"] {
            width: 80px;
            padding: 5px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }

        .file-ops {
            margin-bottom: 20px;
        }

        #jsonFile {
            display: none;
        }

        .status-message {
            padding: 10px;
            margin: 10px 0;
            border-radius: 4px;
            display: none;
        }

        .success {
            background: #dff0d8;
            color: #3c763d;
        }

        .error {
            background: #f2dede;
            color: #a94442;
        }
    </style>
</head>
<body>
    <div class="container">
        <!-- 舵机控制面板 -->
        <div class="panel">
            <h2>舵机控制</h2>
            <div class="file-ops">
                <button onclick="scanServos()">扫描舵机</button>
                <button onclick="bulkOperation('unlock')">全部解锁</button>
                <button onclick="bulkOperation('lock')">全部锁定</button>
            </div>
            <div id="servoList"></div>
        </div>

        <!-- 动作序列面板 -->
        <div class="panel">
            <h2>动作序列</h2>
            <div class="file-ops">
                <button onclick="exportSequence()">导出JSON</button>
                <button onclick="document.getElementById('jsonFile').click()">导入JSON</button>
                <input type="file" id="jsonFile" accept=".json">
            </div>
            <div class="action-controls">
                <button onclick="saveCurrentPosition()">保存当前位置</button>
                <button onclick="executeAllActions()">执行全部动作</button>
            </div>
            <div id="actionList"></div>
        </div>
        
        <!-- 串口操作面板 -->
        <div class="panel">
            <h2>串口操作</h2>
            <div class="file-ops">
                <button onclick="openSerial()">打开串口</button>
            </div>
            <form id="serialForm" style="display: none;">
                <label for="port">串口端口号:</label>
                <input type="text" id="port" name="port" required>
                <br><br>
                <label for="baudrate">波特率:</label>
                <input type="number" id="baudrate" name="baudrate" required>
                <br><br>
                <button type="submit">确认打开</button>
            </form>
        </div>
    </div>

    <div id="statusMessage" class="status-message"></div>

    <script>
        // 全局状态管理
        let currentServos = [];
        
        // 显示状态消息
        function showMessage(message, isError = false) {
            const msgEl = document.getElementById('statusMessage');
            msgEl.textContent = message;
            msgEl.className = `status-message ${isError ? 'error' : 'success'}`;
            msgEl.style.display = 'block';
            setTimeout(() => msgEl.style.display = 'none', 3000);
        }

        // 扫描舵机
        async function scanServos() {
            try {
                const response = await fetch('/scan_servos');
                const data = await response.json();
                currentServos = data.servos;
                updateServoList();
                showMessage(`找到 ${data.servos.length} 个舵机`);
            } catch (error) {
                showMessage(`扫描失败: ${error.message}`, true);
            }
        }

        // 更新舵机列表显示
        async function updateServoList() {
            const container = document.getElementById('servoList');
            const position = await fetch('/get_positions');
            const data = await position.json();
            //showMessage(`当前位置: ${data[1]}`);
            container.innerHTML = currentServos.map(id => `
                <div class="servo-item">
                    <span>舵机 #${id}</span>
                    <div class="controls">
                        <button onclick="adjustPosition(${id}, -10)">-10</button>
                        <button onclick="adjustPosition(${id}, -1)">-1</button>
                        <input type="number" id="pos${id}" value="${data[id]}">
                        <button onclick="adjustPosition(${id}, 1)">+1</button>
                        <button onclick="adjustPosition(${id}, 10)">+10</button>
                    </div>
                    <button id="unlockBtn${id}" onclick="doUnlock(${id})">解锁</button>
                    <button id="lockBtn${id}" onclick="doLock(${id})">锁定</button>
                </div>
            `).join('');
        }
        async function adjustPosition(id, offset) {
            const input = document.getElementById(`pos${id}`);
            const position = parseInt(input.value) + offset;
            //if (position < 0 || position > 180) return;
            input.value = position;
            try {
                const response = await fetch('/set_position', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ id, position })
                });
                const data = await response.json();
                showMessage(data.message);
            } catch (error) {
                showMessage(`设置位置失败: ${error.message}`, true);
            }
            updateServoList();
        }
        // 锁定舵机
        async function doLock(id) {
            try {
                const response = await fetch('/toggle_lock', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ id, lock: true })
                });
                
                const data = await response.json();
                if (data.success) {
                    document.getElementById(`lockBtn${id}`).style.display = 'none';
                    document.getElementById(`unlockBtn${id}`).style.display = 'block';
                    showMessage(data.message);
                } else {
                    throw new Error(data.error);
                }
                updateServoList();
            } catch (error) {
                showMessage(`锁定失败: ${error.message}`, true);
            }
        }
        // 解锁舵机
        async function doUnlock(id) {
            try {
                const response = await fetch('/toggle_lock', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ id, lock: false })
                });
                
                const data = await response.json();
                if (data.success) {
                    document.getElementById(`unlockBtn${id}`).style.display = 'none';
                    document.getElementById(`lockBtn${id}`).style.display = 'block';
                    showMessage(data.message);
                    updateServoList();
                } else {
                    throw new Error(data.error);
                }
            } catch (error) {
                showMessage(`解锁失败: ${error.message}`, true);
            }
        }

        
        // 打开串口
        function openSerial() {
            const form = document.getElementById('serialForm');
            form.style.display = form.style.display === 'none' ? 'block' : 'none';
        }

        // 确认打开串口
        document.getElementById('serialForm').addEventListener('submit', function(event) {
            event.preventDefault(); // 阻止表单的默认提交行为

            const port = document.getElementById('port').value;
            const baudrate = document.getElementById('baudrate').value;

            fetch('/open_serial', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ port: port, baudrate: baudrate })
            })
            .then(response => response.text())
            .then(data => {
                showMessage(data);
            })
            .catch(error => {
                showMessage('发生错误: ' + error, true);
            });
        });

        // 批量操作
        async function bulkOperation(action) {
            try {
                const endpoint = action === 'lock' ? '/bulk_lock' : '/bulk_unlock';
                await fetch(endpoint, { method: 'POST' });
                currentServos.forEach(id => {
                    const btn = document.getElementById(`lockBtn${id}`);
                    if (btn) btn.textContent = action === 'lock' ? '解锁' : '锁定';
                });
            } catch (error) {
                showMessage(`批量操作失败: ${error.message}`, true);
            }
        }

        // 文件操作
        document.getElementById('jsonFile').addEventListener('change', async function(e) {
            const file = e.target.files[0];
            if (!file) return;

            const formData = new FormData();
            formData.append('file', file);

            try {
                const response = await fetch('/import_sequence', {
                    method: 'POST',
                    body: formData
                });
                const result = await response.json();
                if (result.success) {
                    showMessage(result.message);
                    refreshActionList();
                } else {
                    throw new Error(result.error);
                }
            } catch (error) {
                showMessage(`导入失败: ${error.message}`, true);
            }
        });
        
        // 导出动作序列
        async function exportSequence() {
            try {
                const response = await fetch('/export_sequence');
                const data = await response.json();
                const content = JSON.stringify(data, null, 2);
                const blob = new Blob([content], { type: 'application/json' });
                const url = URL.createObjectURL(blob);
                const link = document.createElement('a');
                link.href = url;
                link.download = 'actions.json';
                link.click();
                URL.revokeObjectURL(url);
            } catch (error) {
                showMessage(`导出失败: ${error.message}`, true);
            }
        }

        // 保存当前位置
        async function saveCurrentPosition() {
            try {
                const response = await fetch('/save_action');
                const data = await response.json();
                showMessage(data.message);
                refreshActionList();
            } catch (error) {
                showMessage(`保存失败: ${error.message}`, true);
            }
        }

        // 执行全部动作
        async function executeAllActions() {
            try {
                const response = await fetch('/execute_all_actions');
                const data = await response.json();
                showMessage(data.message);
                refreshActionList();
            } catch (error) {
                showMessage(`执行失败: ${error.message}`, true);
            }
        }

        // 执行单个动作
        async function executeSingleAction(index) {
            try {
                const response = await fetch('/execute_action', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ index })
                });
                const data = await response.json();
                showMessage(data.message);
            } catch (error) {
                showMessage(`执行失败: ${error.message}`, true);
            }
        }

        // 删除动作
        async function deleteAction(index) {
            // 前置验证
            if (isNaN(index) || index < 0) {
                showMessage("无效的序列编号", true);
                return;
            }

            try {
                const response = await fetch('/delete_action', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ index })
                });
                const data = await response.json();
                
                if (!response.ok) {
                    throw new Error(data.error || "未知错误");
                }
                
                showMessage(`${data.message} (剩余${data.new_count}个动作)`);
                refreshActionList();
                
            } catch (error) {
                showMessage(`删除失败: ${error.message}`, true);
                console.error('删除错误:', error);
            }
        }

        // 更新舵机位置
        async function updateServoPosition(id) {
            try {
                const response = await fetch('/get_servo_position', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ id })
                });
                const data = await response.json();
                const input = document.getElementById(`pos${id}`);
                input.value = data.position;
            } catch (error) {
                showMessage(`获取位置失败: ${error.message}`, true);
            }
        }

        // 刷新动作列表
        async function refreshActionList() {
            try {
                const response = await fetch('/get_actions');
                const data = await response.json();
                const container = document.getElementById('actionList');
                
                container.innerHTML = data.actions.map((action, index) => `
                    <div class="action-item">
                        <div class="action-header">
                            <h3>动作 #${index + 1}</h3>
                            <span>延时: ${action.delay}ms</span>
                        </div>
                        <ul>
                            ${action.servos.map(servo => `
                                <li>舵机${servo.id} → 位置: ${servo.position} (模式: ${servo.mode})</li>
                            `).join('')}
                        </ul>
                        <div class="action-buttons">
                            <button onclick="executeSingleAction(${index})">执行</button>
                            <button onclick="deleteAction(${index})">删除</button>
                        </div>
                    </div>
                `).join('');
            } catch (error) {
                showMessage(`加载动作失败: ${error.message}`, true);
            }
        }

        // 初始化加载动作列表
        refreshActionList();
    </script>
</body>
</html>
